package boardData;

import iodevice.CommandPhalanx;

import java.util.Random;
/**
 * Klasse die aus Schachstellungen ZobristKeys erzeugt und die entsprechenden Individualwerte vorhält.
 * Einmal Initalisiert können die Individualwerte nichtmehr geändert werden.
 * @author Hewwa
 * @version V0.1.0 (30.8.'11)
 */
public class ZobirisKeyGenerator {
	private long[][][] pieces = new long[6][2][120]; //[Figur][Besitzer][Feld]
	private long[] casWhite = new long[4];			 //4 Werte in der Rochade aufgrund der Möglichkeiten
	private long[] casBlack = new long[4];			 //Beide seiten, groß, klein, garnix.
	private long[] enPassant = new long[120];		 //120 Felder weil einfacher zu füllen.
	private long sideToMove;						 //Wird angewannt wenn im akuellen Brett schwarz zieht.
	private boolean valuesGenerated = false;
	
	/**
	 * Methode die zu einem gegebenen Brett einen ZobristKey berechnet.
	 * @param board zu dem der Key berechnet werden soll.
	 * @return der Key.
	 */
	public long generateZobirisKey(Board board) {
		long zobirisKey = 0L;
		if(!valuesGenerated)
			generateZobirisValues();
		for(int square = 0; square < 120; square++) {
			if(board.fieldValid(square)){
				int piece = board.getPiece(square);
				if(piece > 0){ //Figur gehöhrt Weiß
					zobirisKey ^= pieces[(Math.abs(piece))-1][0][square];
				} else if(piece < 0){ //Figur gehöhrt Schwarz
					zobirisKey ^= pieces[(Math.abs(piece))-1][1][square];
				}
			}
		}
		zobirisKey ^= casWhite[board.getCasWhite()];
		zobirisKey ^= casBlack[board.getCasBlack()];
		if(board.getEnPassant() != 0)
			zobirisKey ^= enPassant[board.getEnPassant()];
		if(!board.isSideWhite())
			zobirisKey ^= sideToMove;
		return zobirisKey;
	}
	
	/**
	 * Methode die die longwerte für die einzelnen Positionen, Rochademöglichkeiten, EnPassantfelder und die Seite generiert.
	 * Generiert nur dann Werte, wenn nicht schon welche generiert wurden.
	 */
	public void generateZobirisValues() {
		if(!valuesGenerated) {
			CommandPhalanx.infoString("Zobi Zobiris generiert Zobiriswerte!");
			Random generator = new Random();
			for(int i = 0; i < 4; i++) {	//Initialisiere Rochademöglichkeiten
				casWhite[i] = generator.nextLong();
				casBlack[i] = generator.nextLong();
			}
			for(int square = 0; square < 120; square++) { //Schleife für die einzelnen Felder
				for(int piece = 0; piece < 6; piece++) { //Schleife für die Figuren
					for(int side = 0; side < 2; side++) { //Schleife für den Besitzer der Figur
						pieces[piece][side][square] = generator.nextLong();
					}
				}
				enPassant[square] = generator.nextLong();
			}	
			sideToMove = generator.nextLong();
			valuesGenerated = true;
		}
	}
	
	public long getValuePiece(int piece, int square){
		if(!valuesGenerated)
			generateZobirisValues();
		if(piece > 0){ //Figur gehöhrt Weiß
			return pieces[Math.abs(piece)-1][0][square];
		} else if(piece < 0){ //Figur gehöhrt Schwarz
			return pieces[Math.abs(piece)-1][1][square];
		}
		return 0;
	}
	
	public long getValueCas(int casPosibilities, boolean sideWhite){
		if(!valuesGenerated)
			generateZobirisValues();
		if(sideWhite)
			return casWhite[casPosibilities];
		return casBlack[casPosibilities];	
	}
	
	public long getValueEnPassant(int square) {
		if(!valuesGenerated)
			generateZobirisValues();
		return enPassant[square];
	}
	
	public long getValueSideToMove() {
		if(!valuesGenerated)
			generateZobirisValues();
		return sideToMove;
	}
}